/**
 * ============JWT令牌工具模块开始===========
 * JWT令牌工具 - JWT Token Utility
 * 
 * 功能说明：
 * - 提供JWT令牌的生成和验证功能
 * - 支持用户身份认证和授权
 * - 集成环境变量配置
 * - 提供安全的令牌管理机制
 * 
 * 依赖模块：
 * - jsonwebtoken: JWT令牌处理库
 * 
 * 令牌特性：
 * - 无状态认证机制
 * - 支持过期时间设置
 * - 包含用户身份信息
 * - 支持签名验证
 * 
 * 应用场景：
 * - 用户登录后生成访问令牌
 * - API请求身份验证
 * - 用户会话管理
 * - 权限控制和授权
 * 
 * 设计原则：
 * - 安全性优先，使用强密钥
 * - 合理的过期时间设置
 * - 统一的令牌格式
 * - 完善的错误处理
 * 
 * Provides JWT token generation and verification with security best practices
 */

// 导入必要的依赖包 - Import necessary dependencies
import jwt from "jsonwebtoken";                                   // JWT令牌处理库 - JWT token processing library

/**
 * ============令牌生成函数开始===========
 * 生成JWT访问令牌 - Generate JWT access token
 * 
 * @param {string|number} userId - 用户ID，用于标识令牌所属用户
 * @param {Object} options - 可选配置参数
 * @param {string} options.role - 用户角色（可选）
 * @param {Object} options.permissions - 用户权限（可选）
 * @param {string} options.expiresIn - 过期时间（可选，覆盖默认设置）
 * @returns {string} 生成的JWT令牌字符串
 * 
 * 功能说明：
 * - 使用用户ID生成唯一的JWT令牌
 * - 支持自定义过期时间和附加信息
 * - 使用环境变量中的密钥进行签名
 * - 返回可用于身份验证的令牌字符串
 * 
 * 令牌结构：
 * - Header: 包含算法和令牌类型信息
 * - Payload: 包含用户ID、过期时间等声明
 * - Signature: 使用密钥生成的签名，确保令牌完整性
 * 
 * 安全考虑：
 * - 使用强密钥进行签名（建议32位以上随机字符串）
 * - 设置合理的过期时间（默认7天）
 * - 不在令牌中存储敏感信息（如密码）
 * - 定期轮换JWT密钥以提高安全性
 * 
 * 使用示例：
 * // 基本用法
 * const token = generateToken(123);
 * 
 * // 带角色信息
 * const adminToken = generateToken(456, { 
 *   role: 'admin',
 *   permissions: ['read', 'write', 'delete']
 * });
 * 
 * // 自定义过期时间
 * const shortToken = generateToken(789, { expiresIn: '1h' });
 * 
 * 环境变量配置：
 * - JWT_SECRET: JWT签名密钥（生产环境必须设置）
 * - TOKEN_EXPIRES_IN: 令牌过期时间（默认7天）
 */
export const generateToken = (userId, options = {}) => {
  // 第一步：获取JWT密钥 - Step 1: Get JWT secret
  const secret = process.env.JWT_SECRET || "fortune-dev-secret";
  
  // 第二步：获取过期时间配置 - Step 2: Get expiration time configuration
  const expiresIn = options.expiresIn || process.env.TOKEN_EXPIRES_IN || "7d";
  
  // 第三步：构建令牌载荷 - Step 3: Build token payload
  const payload = {
    userId: userId,                                               // 用户ID - User ID
    iat: Math.floor(Date.now() / 1000),                         // 签发时间 - Issued at time
    ...options.role && { role: options.role },                  // 用户角色（可选）- User role (optional)
    ...options.permissions && { permissions: options.permissions } // 用户权限（可选）- User permissions (optional)
  };
  
  // 第四步：生成并返回JWT令牌 - Step 4: Generate and return JWT token
  return jwt.sign(payload, secret, { 
    expiresIn,                                                   // 过期时间 - Expiration time
    algorithm: 'HS256',                                          // 签名算法 - Signing algorithm
    issuer: 'fortune-app',                                       // 令牌签发者 - Token issuer
    audience: 'fortune-users'                                    // 令牌受众 - Token audience
  });
};

/**
 * ============令牌验证函数开始===========
 * 验证JWT访问令牌 - Verify JWT access token
 * 
 * @param {string} token - 需要验证的JWT令牌字符串
 * @returns {Object} 解码后的令牌载荷对象
 * @throws {JsonWebTokenError} 令牌格式无效时抛出错误
 * @throws {TokenExpiredError} 令牌过期时抛出错误
 * @throws {NotBeforeError} 令牌尚未生效时抛出错误
 * 
 * 功能说明：
 * - 验证JWT令牌的签名和完整性
 * - 检查令牌是否过期
 * - 解码并返回令牌中的用户信息
 * - 提供详细的错误信息用于调试
 * 
 * 验证过程：
 * 1. 检查令牌格式是否正确
 * 2. 使用密钥验证令牌签名
 * 3. 检查令牌是否过期
 * 4. 验证令牌的签发者和受众
 * 5. 返回解码后的用户信息
 * 
 * 返回对象结构：
 * {
 *   userId: string|number,     // 用户ID
 *   role?: string,             // 用户角色（可选）
 *   permissions?: Array,       // 用户权限（可选）
 *   iat: number,              // 签发时间戳
 *   exp: number,              // 过期时间戳
 *   iss: string,              // 签发者
 *   aud: string               // 受众
 * }
 * 
 * 错误处理：
 * - JsonWebTokenError: 令牌格式错误或签名无效
 * - TokenExpiredError: 令牌已过期，需要重新登录
 * - NotBeforeError: 令牌尚未生效
 * - 其他错误: 验证过程中的其他异常
 * 
 * 使用示例：
 * try {
 *   const decoded = verifyToken(token);
 *   console.log('用户ID:', decoded.userId);
 *   console.log('用户角色:', decoded.role);
 *   console.log('令牌过期时间:', new Date(decoded.exp * 1000));
 * } catch (error) {
 *   if (error.name === 'TokenExpiredError') {
 *     console.log('令牌已过期，请重新登录');
 *   } else if (error.name === 'JsonWebTokenError') {
 *     console.log('无效的令牌格式');
 *   } else {
 *     console.log('令牌验证失败:', error.message);
 *   }
 * }
 * 
 * 安全注意事项：
 * - 始终在try-catch块中使用此函数
 * - 不要在客户端存储敏感的令牌信息
 * - 定期检查令牌的有效性
 * - 在令牌过期时及时清理客户端存储
 */
export const verifyToken = (token) => {
  // 第一步：获取JWT密钥 - Step 1: Get JWT secret
  const secret = process.env.JWT_SECRET || "fortune-dev-secret";
  
  // 第二步：验证令牌并返回载荷 - Step 2: Verify token and return payload
  try {
    // 使用密钥验证令牌，包含完整性和过期时间检查 - Verify token with secret, including integrity and expiration checks
    const decoded = jwt.verify(token, secret, {
      algorithms: ['HS256'],                                     // 允许的签名算法 - Allowed signing algorithms
      issuer: 'fortune-app',                                     // 验证签发者 - Verify issuer
      audience: 'fortune-users'                                  // 验证受众 - Verify audience
    });
    
    return decoded;                                              // 返回解码后的令牌载荷 - Return decoded token payload
  } catch (error) {
    // 重新抛出错误，保持原始错误类型和消息 - Re-throw error, maintaining original error type and message
    throw error;
  }
};

/**
 * ============令牌刷新函数开始===========
 * 刷新JWT访问令牌 - Refresh JWT access token
 * 
 * @param {string} oldToken - 旧的JWT令牌（即将过期或已过期）
 * @returns {string|null} 新的JWT令牌，如果旧令牌无效则返回null
 * 
 * 功能说明：
 * - 基于旧令牌生成新的访问令牌
 * - 延长用户会话时间
 * - 保持用户登录状态
 * - 提供无缝的令牌更新机制
 * 
 * 刷新策略：
 * - 验证旧令牌的有效性（忽略过期时间）
 * - 提取用户信息和权限
 * - 生成新的令牌并返回
 * - 保持原有的用户角色和权限
 * 
 * 使用示例：
 * const newToken = refreshToken(expiredToken);
 * if (newToken) {
 *   // 更新客户端存储的令牌
 *   localStorage.setItem('token', newToken);
 * } else {
 *   // 令牌无法刷新，需要重新登录
 *   redirectToLogin();
 * }
 */
export const refreshToken = (oldToken) => {
  try {
    // 第一步：验证旧令牌（忽略过期时间）- Step 1: Verify old token (ignore expiration)
    const secret = process.env.JWT_SECRET || "fortune-dev-secret";
    const decoded = jwt.verify(oldToken, secret, { 
      ignoreExpiration: true,                                    // 忽略过期时间 - Ignore expiration
      algorithms: ['HS256']
    });
    
    // 第二步：生成新令牌 - Step 2: Generate new token
    return generateToken(decoded.userId, {
      role: decoded.role,
      permissions: decoded.permissions
    });
  } catch (error) {
    // 旧令牌无效，无法刷新 - Old token is invalid, cannot refresh
    return null;
  }
};

/**
 * ============令牌解码函数开始===========
 * 解码JWT令牌（不验证签名）- Decode JWT token (without signature verification)
 * 
 * @param {string} token - 需要解码的JWT令牌
 * @returns {Object|null} 解码后的令牌载荷，如果解码失败则返回null
 * 
 * 功能说明：
 * - 仅解码令牌内容，不验证签名
 * - 用于获取令牌中的基本信息
 * - 不保证令牌的有效性和完整性
 * - 主要用于调试和信息展示
 * 
 * 注意事项：
 * - 此函数不验证令牌签名，不应用于安全验证
 * - 仅用于获取令牌中的非敏感信息
 * - 在生产环境中谨慎使用
 * 
 * 使用示例：
 * const tokenInfo = decodeToken(token);
 * if (tokenInfo) {
 *   console.log('令牌过期时间:', new Date(tokenInfo.exp * 1000));
 *   console.log('用户ID:', tokenInfo.userId);
 * }
 */
export const decodeToken = (token) => {
  try {
    // 解码令牌但不验证签名 - Decode token without signature verification
    return jwt.decode(token);
  } catch (error) {
    // 解码失败，返回null - Decode failed, return null
    return null;
  }
};

/**
 * ============令牌工具导出说明开始===========
 * 导出JWT令牌工具供应用使用
 * Export JWT token utilities for application use
 * 
 * 导出说明：
 * - generateToken: 生成JWT访问令牌
 * - verifyToken: 验证JWT令牌有效性
 * - refreshToken: 刷新JWT令牌
 * - decodeToken: 解码JWT令牌内容
 * 
 * 使用示例：
 * import { generateToken, verifyToken, refreshToken, decodeToken } from './utils/token.js';
 * 
 * // 在用户登录时生成令牌
 * export const loginUser = async (req, res) => {
 *   try {
 *     const user = await authenticateUser(req.body);
 *     const token = generateToken(user.id, { 
 *       role: user.role,
 *       permissions: user.permissions 
 *     });
 *     
 *     res.json({ 
 *       success: true, 
 *       token,
 *       user: { id: user.id, email: user.email, role: user.role }
 *     });
 *   } catch (error) {
 *     res.status(401).json({ message: '登录失败' });
 *   }
 * };
 * 
 * // 在认证中间件中验证令牌
 * export const authMiddleware = (req, res, next) => {
 *   try {
 *     const token = req.headers.authorization?.replace('Bearer ', '');
 *     const decoded = verifyToken(token);
 *     req.user = decoded;
 *     next();
 *   } catch (error) {
 *     if (error.name === 'TokenExpiredError') {
 *       res.status(401).json({ message: '令牌已过期' });
 *     } else {
 *       res.status(401).json({ message: '无效的令牌' });
 *     }
 *   }
 * };
 * 
 * // 在令牌刷新端点中使用
 * export const refreshTokenEndpoint = (req, res) => {
 *   const oldToken = req.body.token;
 *   const newToken = refreshToken(oldToken);
 *   
 *   if (newToken) {
 *     res.json({ success: true, token: newToken });
 *   } else {
 *     res.status(401).json({ message: '无法刷新令牌，请重新登录' });
 *   }
 * };
 * 
 * 最佳实践：
 * - 在生产环境中使用强密钥（JWT_SECRET）
 * - 设置合理的令牌过期时间
 * - 实现令牌刷新机制以提升用户体验
 * - 在客户端安全存储令牌（避免XSS攻击）
 * - 定期轮换JWT密钥以提高安全性
 * - 在令牌中避免存储敏感信息
 * - 实现令牌黑名单机制（如需要）
 */

// ============JWT令牌工具模块结束===========
